package istring

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

// ToString converts a value to string.
func ToString(value interface{}) string {
	switch value := value.(type) {
	case string:
		return value
	case int8:
		return strconv.FormatInt(int64(value), 10)
	case int16:
		return strconv.FormatInt(int64(value), 10)
	case int32:
		return strconv.FormatInt(int64(value), 10)
	case int64:
		return strconv.FormatInt(value, 10)
	case uint8:
		return strconv.FormatUint(uint64(value), 10)
	case uint16:
		return strconv.FormatUint(uint64(value), 10)
	case uint32:
		return strconv.FormatUint(uint64(value), 10)
	case uint64:
		return strconv.FormatUint(value, 10)
	case float32:
		return strconv.FormatFloat(float64(value), 'g', -1, 64)
	case float64:
		return strconv.FormatFloat(value, 'g', -1, 64)
	case bool:
		return strconv.FormatBool(value)
	default:
		return fmt.Sprintf("%+v", value)
	}
}

// IsEmpty 判断字符串为空
func IsEmpty(value string) bool {
	return len(value) == 0
}

// IsNotEmpty 判断字符串非空
func IsNotEmpty(value string) bool {
	return !IsEmpty(value)
}

// EqualsIgnoreCase 比较字符串相等
func EqualsIgnoreCase(a, b string) bool {
	return strings.EqualFold(a, b)
}

// StartWithIgnoreCase 字符前缀判断
func StartWithIgnoreCase(source, prefix string) bool {
	caseSource := strings.ToUpper(source)
	casePrefix := strings.ToUpper(prefix)
	return strings.HasPrefix(caseSource, casePrefix)
}

// EndWithIgnoreCase 字符后缀判断
func EndWithIgnoreCase(source, suffix string) bool {
	caseSource := strings.ToUpper(source)
	caseSuffix := strings.ToUpper(suffix)
	return strings.HasSuffix(caseSource, caseSuffix)
}

// Compare 字符串比较大小
func Compare(base, compare string) int {
	return strings.Compare(base, compare)
}

// SubstringBeforeFirst 字符串截取
func SubstringBeforeFirst(source string, sep string) string {
	index := strings.Index(source, sep)
	if index >= 0 {
		return source[0:index]
	}
	return source
}

// SubstringAfterLast 字符串截取
func SubstringAfterLast(source string, sep string) string {
	index := strings.LastIndex(source, sep)
	if index >= 0 {
		return source[index+1 : len(source)]
	}
	return source
}

func ReplaceFirst(s, old, new string) string {
	return strings.Replace(s, old, new, 1)
}

// StringReplaceContext 字符串占位符替换 占位符为"${name}" => 占位符仅支持: 英文数字下划线中划线
func StringReplaceContext(s string, context map[string]string) (string, error) {
	reg := regexp.MustCompile("\\${\\s*[a-zA-Z0-9_-]+\\s*}")
	matched := reg.FindAllString(s, -1)
	result := s
	fmt.Println(matched)
	for _, v := range matched {
		key := strings.Replace(v, "${", "", -1)
		key = strings.Replace(key, "}", "", -1)
		key = strings.Replace(key, " ", "", -1)
		value := context[key]
		fmt.Println("map value:", v, key, value)
		result = strings.Replace(result, v, value, -1)
	}
	return result, nil
}

// Format 字符串 Logback 格式替换 => 占位符 {}
func Format(s string, a ...interface{}) (string, error) {
	reg := regexp.MustCompile("\\{\\s*\\}")
	matched := reg.FindAllString(s, -1)
	for i := 0; i < len(matched); i++ {
		oldStr := matched[i]
		newStr := ""
		if i < len(a) {
			newStr = ToString(a[i])
		}
		s = strings.Replace(s, oldStr, newStr, 1)
	}
	return s, nil
}

func FormatIgnoreError(s string, a ...interface{}) string {
	reg := regexp.MustCompile("\\{\\s*\\}")
	matched := reg.FindAllString(s, -1)
	for i := 0; i < len(matched); i++ {
		oldStr := matched[i]
		newStr := ""
		if i < len(a) {
			newStr = ToString(a[i])
		}
		s = strings.Replace(s, oldStr, newStr, 1)
	}
	return s
}

func Log(s string, a ...interface{}) {
	result := FormatIgnoreError(s, a)
	fmt.Println(result)
}

// Contains 判断 source 是否包含 contained
func Contains(source string, sub string) bool {
	return strings.Contains(source, sub)
}

// ToUpperCase 转大写
func ToUpperCase(source string) string {
	return strings.ToUpper(source)
}

// ToLowerCase 转小写
func ToLowerCase(source string) string {
	return strings.ToLower(source)
}

// ToBool 取得整型值所表达的布尔类型;不同于golang提供的ParseBool
func ToBool(value string) (bool, error) {
	return strconv.ParseBool(value)
}

// ToSnakeCase 匈牙利命名法, 转换小写下划线, XxYy to xx_yy , XxYY to xx_y_y
func ToSnakeCase(s string) string {
	data := make([]byte, 0, len(s)*2)
	j := false
	num := len(s)
	for i := 0; i < num; i++ {
		d := s[i]
		if i > 0 && d >= 'A' && d <= 'Z' && j {
			data = append(data, '_')
		}
		if d != '_' {
			j = true
		}
		data = append(data, d)
	}
	return strings.ToLower(string(data[:]))
}

// ToCamelCase 转换为大驼峰写法, xx_yy to XxYy
func ToCamelCase(s string) string {
	data := make([]byte, 0, len(s))
	flag, num := true, len(s)-1
	for i := 0; i <= num; i++ {
		d := s[i]
		if d == '_' {
			flag = true
			continue
		} else if flag {
			if d >= 'a' && d <= 'z' {
				d = d - 32
			}
			flag = false
		}
		data = append(data, d)
	}
	return string(data[:])
}
